#ifndef __AFDCPP_H__
#define __AFDCPP_H__
#include "misc.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <list>
#include <map>
#include <string>
#include <algorithm>
#include <sstream>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
//#include <boost/graph/graphviz.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/graph/connected_components.hpp>		//find not connected components
#include <boost/graph/biconnected_components.hpp>	//find weak connected components
#include <boost/graph/subgraph.hpp>					//subgraph
#include <boost/graph/vertex_and_edge_range.hpp>  // edge_range function for parallel edges
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/random.hpp>      //random num seq
#include <boost/tuple/tuple.hpp>  // for tuples ala std::pair
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/graph/kamada_kawai_spring_layout.hpp> //layout algorithm
#include <boost/graph/random_layout.hpp>
#include <boost/graph/circle_layout.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <iterator>
#include <utility>
#include <ginac/ginac.h>
#include <ginac/flags.h> // needed by is_a<T> funcs
////#include <combination.hpp>     // Internal combinator funcs
#include <xloops.h> //one loop analytic expressions
#include <sector_decomposition/sector_decomposition.h>
#include <dbstl_vector.h>

//#include <FeynDiagram/fd.h> //  FeynDiagram header

#include "drawer.h"
#include "utils.h"
//#include "misc.h"

using namespace GiNaC;
using namespace boost;
using namespace xloops;
using std::cout;
using std::endl;
using std::string;
using std::setw;
using std::make_pair;
using std::pair;

/// Classes for diagram drawing and PS output 



/// Type for halfedge storage after M(G) in T(G) function
typedef std::list< tuple<Graph::vertex_descriptor,Graph::edge_descriptor,field,ex> > tuple_lst;
/// Tuple for function get_ext_vert()
typedef std::list< tuple<Graph::vertex_descriptor,field,ex> > ext_vert_mom_field_tuple_lst;



class afdcpp
{   
  ex m1,m2,m3;
  /// All indices in vertices are contravariant
  ex EeA(varidx& index);
  ex BbZ(varidx& index);
  ex BbGZ();
  ex roZ(varidx& index, ex& mom1, ex& mom2, ex& mom3);
  ///Spinor propagators
  ex S(symbol& sim,ex& mom);
  ex B(symbol& sim,ex& mom);
  /// Gauge bosons propagators 
  /// All indices in propagators are covariant
  ex D(symbol& sim,ex& mom,varidx& v_to,varidx& v_from);
  ex Z(symbol& sim,ex& mom,varidx& v_to,varidx& v_from);
  /// Goldstone bosons propagators
  ex GZ(symbol& sim,ex& mom);


  scalar_products global_sp();
 /// main vectors for diagram storing
  gVec gv11;
  //dbstl::db_vector<Graph>  gv11;
  lst in_dia_ex;
  map_ext_legs ext_legs;  
  ///Temporary list for subgraphs of graph;
  //Graph_1PI_lst tmplst;

  /// main list of momentum scalar products
  scalar_products gsp;



  /// internal
  //  static edge_component_t edge_component;
  // static graph_num_t graph_num;
  // static graph_factor_t graph_factor;
  /// internal

  drawer dr1;

  void init();
  //  ex ex_from_graph(Graph);
  bool has_par_edges(Graph::edge_descriptor,Graph);
  //bool is_external_vert(Graph::vertex_descriptor&,Graph&);
  //void print(Graph&);
  std::string draw(Graph&);
  void draw2(Graph&,FD::page&);
  //  void draw_lst(Graph_1PI_lst&);
  /// random num gen for draw
  boost::mt19937 draw_rand; 
  void fill_in_dia_ex();
  void reduze_out(ex);
  void reduze_in_dia_ex();
  ex scalarize_vectors(ex);
  ex scalarize_l_vectors(ex);
  ex subs_ext_mom(GiNaC::ex, GiNaC::exvector);
  void feynman(ex,exvector,exvector);
  /// Prepare diagram
  ex ex_prepare(ex);
  /// Differentiation functions
  ex divpoly(ex,ex,varidx);
  void divrat(ex,ex);
  /// R-operation functions
  void M(Graph&);
  Graph T(Graph&);
  Graph K(Graph&,Graph&);
  std::pair<Graph,Graph> K2(Graph&,Graph&);
  //  bool isWeakConnected(Graph&);
  //bool isNotConnected(Graph&);
  //  bool isConnected(Graph&);
  //  int diagIndex(Graph&);
  ex term_ex(std::list<Graph>&);
  //ex get_terms(Graphref_lst);  
  //  ex projector(Graph&);
  ex int_graph(Graph);
  ex div_part(Graph&);
  void qed_renorm();
  void scalar_renorm();
  exvector loop_momentum(ex,exvector);
  //void inc(std::vector<bool>&);
  //void operator++(std::vector< bool > &);
  // bool is_full(std::vector<bool>);
  void mark_ext_vert(Graph&);
  //  int num_ext_vert(Graph&);
  ext_vert_mom_field_tuple_lst get_ext_legs(Graph&);
  std::vector<field> get_ext_fields(Graph&);
  exvector get_ext_momentum(Graph&);
  ex get_ext_mom_of_vertex(Graph::vertex_descriptor,Graph&);
  std::pair<ex,bool> get_global_ext_mom_info(Graph::vertex_descriptor,Graph&);
  tuple<int,ex,ex> T_expr_prop(field,field,int,int,ex);
  std::pair<ex,ex> T_expr3(Graph::vertex_descriptor&,tuple_lst&,ext_vert_mom_field_tuple_lst&);
  std::pair<ex,ex> T_expr4(Graph::vertex_descriptor&,tuple_lst&,ext_vert_mom_field_tuple_lst&);
  //  Graph_1PI_lst make_subgraphs(Graph&);
  void dred();

  /// Package LOGO =)
  //  void logo();
 public:
  afdcpp();
};
#endif
